<template>
  <div class="app-container">
    <div class="app-content-container">
      <grid-table
        ref="gridTable"
        border="inner"
        name="JobManager"
        :loading.sync="loading"
        :query="queryParams"
        show-overflow
        :buttons.sync="buttons"
        :perfect="false"
        :show-search="true"
        :columns="tableColumns"
        :table-data="jobList"
        @current-change="handleCurrentChange"
        @cell-dblclick="handleUpdate"
        @remote-method="getList">
        <template v-slot:search-form>
          <el-form :model="queryParams" size="mini" ref="queryForm" :inline="true" class="inline-form" v-show="showSearch">
            <el-form-item label="任务名称" prop="jobName">
              <el-input
                v-model="queryParams.jobName"
                placeholder="请输入任务名称"
                clearable
                @keyup.enter.native="handleQuery"/>
            </el-form-item>
            <el-form-item label="任务组名" prop="jobGroup">
              <el-select v-model="queryParams.jobGroup" placeholder="请选择任务组名" clearable>
                <el-option
                  v-for="dict in jobGroupOptions"
                  :key="dict.dictValue"
                  :label="dict.dictLabel"
                  :value="dict.dictValue"
                />
              </el-select>
            </el-form-item>
            <el-form-item label="任务状态" prop="status">
              <el-select v-model="queryParams.status" placeholder="请选择任务状态" clearable>
                <el-option
                  v-for="dict in statusOptions"
                  :key="dict.dictValue"
                  :label="dict.dictLabel"
                  :value="dict.dictValue"
                />
              </el-select>
            </el-form-item>
          </el-form>
        </template>
      </grid-table>
    </div>
    <!-- 添加或修改定时任务对话框 -->
    <vxe-modal
      v-model="open"
      :z-index="100"
      :esc-closable="true"
      transfer
      show-footer
      lock-view
      lock-scroll
      :position="{ top: 100, left: 'center' }"
      :title="title"
      destroy-on-close
      width="750px"
      height="50%"
      resize>
      <template v-slot>
        <el-form ref="form" size="mini" :inline="true" :model="form" :rules="rules" label-width="110px">
          <el-row>
              <el-form-item label="任务名称" prop="jobName">
                <el-input v-model="form.jobName" placeholder="请输入任务名称" />
              </el-form-item>
              <el-form-item label="任务分组" prop="jobGroup">
                <el-select v-model="form.jobGroup" placeholder="请选择">
                  <el-option
                    v-for="dict in jobGroupOptions"
                    :key="dict.dictValue"
                    :label="dict.dictLabel"
                    :value="dict.dictValue"
                  ></el-option>
                </el-select>
              </el-form-item>
          </el-row>
          <el-row>
            <el-form-item prop="invokeTarget">
              <span slot="label">
                调用方法
                <el-tooltip placement="top" style="display: inline">
                  <div slot="content">
                    Bean调用示例：ryTask.ryParams('ry')
                    <br />Class类调用示例：RyTask.ryParams('ry')
                    <br />参数说明：支持字符串，布尔类型，长整型，浮点型，整型
                  </div>
                  <i class="el-icon-question"></i>
                </el-tooltip>
              </span>
              <el-input v-model="form.invokeTarget" class="form-item--medium" placeholder="请输入调用方法字符串"/>
            </el-form-item>
          </el-row>
          <el-row>
            <el-form-item label="错误策略" prop="misfirePolicy">
              <el-radio-group v-model="form.misfirePolicy" size="mini">
                <el-radio-button label="1">立即运行</el-radio-button>
                <el-radio-button label="2">运行一次</el-radio-button>
                <el-radio-button label="3">放弃运行</el-radio-button>
              </el-radio-group>
            </el-form-item>
            <el-form-item label="是否并发" prop="concurrent">
              <el-radio-group v-model="form.concurrent" size="mini">
                <el-radio-button label="0">允许</el-radio-button>
                <el-radio-button label="1">禁止</el-radio-button>
              </el-radio-group>
            </el-form-item>
          </el-row>
          <el-row>
            <el-form-item label="cron表达式" prop="cronExpression">
              <el-popover v-model="cronPopover" transition="none" :open-delay="0" :close-delay="0">
                <el-input slot="reference" v-model="form.cronExpression" @click="cronPopover=true" placeholder="请输入cron执行表达式" />
                <vue-cron @change="handleCronChange"
                          @close="cronPopover=false"
                          i18n="cn">
                </vue-cron>
              </el-popover>
            </el-form-item>
          </el-row>
          <el-row>
            <el-form-item label="状态">
              <el-radio-group v-model="form.status">
                <el-radio
                  v-for="dict in statusOptions"
                  :key="dict.dictValue"
                  :label="dict.dictValue"
                >{{dict.dictLabel}}</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-row>
        </el-form>
      </template>
      <template v-slot:footer>
        <el-button type="primary" @click="submitForm">确 定</el-button>
        <el-button @click="cancel">取 消</el-button>
      </template>
    </vxe-modal>
    <!-- 任务日志详细 -->
    <vxe-modal
      v-model="openView"
      :z-index="100"
      :esc-closable="true"
      transfer
      show-footer
      lock-view
      lock-scroll
      :position="{ top: 100, left: 'center' }"
      title="任务运行详情"
      destroy-on-close
      width="750px"
      height="50%"
      resize>
      <el-form ref="form" :model="form" label-width="140px" size="mini">
        <el-row>
          <el-col :span="12">
            <el-form-item label="任务编号：">{{ form.jobId }}</el-form-item>
            <el-form-item label="任务名称：">{{ form.jobName }}</el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="任务分组：">{{ jobGroupFormat(form) }}</el-form-item>
            <el-form-item label="创建时间：">{{ form.createTime }}</el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="cron表达式：">{{ form.cronExpression }}</el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="更新时间：">{{ parseTime(form.updateTime) }}</el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="调用方法：">{{ form.invokeTarget }}</el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="任务状态：">
              <el-tag type="success" v-if="form.status == 0">正常</el-tag>
              <el-tag type="danger" v-else-if="form.status == 1">暂停</el-tag>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="是否并发：">
              <div v-if="form.concurrent == 0">允许</div>
              <div v-else-if="form.concurrent == 1">禁止</div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="执行策略：">
              <div v-if="form.misfirePolicy == 0">默认策略</div>
              <div v-else-if="form.misfirePolicy == 1">立即执行</div>
              <div v-else-if="form.misfirePolicy == 2">执行一次</div>
              <div v-else-if="form.misfirePolicy == 3">放弃执行</div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="失败重试次数：">
              <span>{{ form.failRetryCount }}</span>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="上次运行时间：">
              <span>{{ form.lastRunTime }}</span>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="上次成功运行时间：">
              <span>{{ form.lastSuccessRunTime }}</span>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template v-slot:footer>
        <el-button @click="openView = false">关 闭</el-button>
      </template>
    </vxe-modal>
  </div>
</template>

<script>
import { listJob, getJob, delJob, addJob, updateJob, exportJob, runJob, changeJobStatus } from "@/api/monitor/job";
import cronstrue from 'cronstrue/i18n';
import GridTable from '@/components/GridTable'

export default {
  name: "Job",
  components: { GridTable },
  data() {
    return {
      buttons: [
        { type: 'import', disabled: true },
        { type: 'add', click: this.handleAdd, permit: 'monitor:job:add' },
        { type: 'edit', click: this.handleUpdate, permit: 'monitor:job:update' },
        { type: 'delete', click: this.handleDelete, permit: 'monitor:job:remove' },
        { type: 'search', click: this.handleQuery, permit: 'monitor:job:query'},
        { type: 'reset', click: this.resetQuery, permit: 'monitor:job:query'},
        { type: 'export', click: this.handleExport, permit: 'monitor:job:export'},
        { type: 'custom', name: '日志', icon: 'log', click: this.handleJobLog, permit: 'monitor:job:query' }
      ],
      tableColumns: [
        { title: '任务编号', width: 80, field: 'jobId', align: 'center', headerAlign: 'center' },
        { title: '任务组', width: 120, field: 'jobGroup', headerAlign: 'center', align: 'center' },
        { title: '任务名称', width: 240, field: 'jobName', headerAlign: 'center', align: 'center'},
        { title: '调用方法', width: "auto", field: 'invokeTarget', headerAlign: 'center', align: 'center'},
        { title: '上次触发时间', width: 180, field: 'triggerLastTime', headerAlign: 'center', align: 'center'},
        { title: '下次触发时间', width: 180, field: 'triggerNextTime', headerAlign: 'center', align: 'center'},
        { title: '状态', width: 160, headerAlign: 'center', align: 'center',
          slots: {
            default: ({ row }) => {
              const activeValue = "0";
              const inactiveValue = "1";
              return [<el-switch
                        v-model={row.status}
                        active-value={activeValue}
                        inactive-value={inactiveValue}
                        on-change={ () => { this.handleStatusChange(row) }}>
                      </el-switch>
                ]
            }
          }
        },
        {
          title: 'cron表达式', width: 160, headerAlign: 'center', align: 'center',
          slots: {
            default: ({ row }) => {
              const closeDelay = 0
              const openDelay = 0
              return [
                <el-popover trigger="hover" placement="bottom" close-delay={ closeDelay } open-delay={ openDelay } transition="none">
                  { this.humanlizeCronExpression(row.cronExpression) }
                  <div slot="reference">
                    <el-tag size="medium">{row.cronExpression}</el-tag>
                  </div>
                </el-popover>
              ]
            }
          }
        },
        {
          title: '操作', width: 160, headerAlign: 'center', align: 'center',
          slots: {
            default: ({ row }) => {
              return [
                <div>
                  <el-button
                    size="mini"
                    type="text"
                    icon="el-icon-video-play"
                    nativeOnClick={ () => { this.handleRun(row) } }
                    >运行</el-button>
                  <el-button
                    size="mini"
                    type="text"
                    icon="el-icon-view"
                    nativeOnClick={ () => { this.handleView(row) } }
                    >详情</el-button>
                  <el-button
                    size="mini"
                    type="text"
                    icon="el-icon-document"
                    nativeOnClick={ () => { this.handleJobLog(row.jobId) } }
                    >日志</el-button>
                </div>
              ]
            }
          }
        }
      ],
      //
      running: false,
      // cron选择器
      cronPopover: false,
      // 遮罩层
      loading: true,
      // 选中数组
      ids: [],
      // 非单个禁用
      single: true,
      // 非多个禁用
      multiple: true,
      // 显示搜索条件
      showSearch: true,
      // 总条数
      total: 0,
      // 定时任务表格数据
      jobList: [],
      // 弹出层标题
      title: "",
      // 是否显示弹出层
      open: false,
      // 是否显示详细弹出层
      openView: false,
      // 任务组名字典
      jobGroupOptions: [],
      // 状态字典
      statusOptions: [],
      // 查询参数
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        jobName: undefined,
        jobGroup: undefined,
        status: undefined
      },
      // 表单参数
      form: {},
      // 表单校验
      rules: {
        jobName: [
          { required: true, message: "任务名称不能为空", trigger: "blur" }
        ],
        invokeTarget: [
          { required: true, message: "调用方法不能为空", trigger: "blur" }
        ],
        cronExpression: [
          { required: true, message: "cron执行表达式不能为空", trigger: "blur" }
        ]
      },
      currentRow: undefined
    };
  },
  created() {
    this.getList();
    this.getDicts("sys_job_group").then(response => {
      this.jobGroupOptions = response.data;
    });
    this.getDicts("sys_job_status").then(response => {
      this.statusOptions = response.data;
    });
  },
  methods: {
    handleCurrentChange({ row }) {
      this.currentRow = row
    },
    /** 查询定时任务列表 */
    getList() {
      this.loading = true;
      listJob(this.queryParams).then(response => {
        this.jobList = response.rows;
        this.total = response.total;
        this.loading = false;
      });
    },
    humanlizeCronExpression(val) {
      return cronstrue.toString(val, { locale: 'zh_CN' })
    },
    handleCronChange(expr) {
      this.form.cronExpression = expr
    },
    // 任务组名字典翻译
    jobGroupFormat(row, column) {
      return this.selectDictLabel(this.jobGroupOptions, row.jobGroup);
    },
    // 状态字典翻译
    statusFormat(row, column) {
      return this.selectDictLabel(this.statusOptions, row.status);
    },
    // 取消按钮
    cancel() {
      this.open = false;
      this.reset();
    },
    // 表单重置
    reset() {
      this.form = {
        jobId: undefined,
        jobName: undefined,
        jobGroup: undefined,
        invokeTarget: undefined,
        cronExpression: undefined,
        misfirePolicy: 1,
        concurrent: 1,
        status: "0"
      };
      this.resetForm("form");
    },
    /** 搜索按钮操作 */
    handleQuery() {
      this.queryParams.pageNum = 1;
      this.getList();
    },
    /** 重置按钮操作 */
    resetQuery() {
      this.resetForm("queryForm");
      this.handleQuery();
    },
    // 多选框选中数据
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.jobId);
      this.single = selection.length != 1;
      this.multiple = !selection.length;
    },
    // 任务状态修改
    handleStatusChange(row) {
      const that = this;
      const newStatus = row.status
      row.status = newStatus === '0' ? '1' : '0' //保持switch点击前的状态
      let text = row.status === "0" ? "停用" : "启用";
      this.$XModal.confirm('确认要' + text + '"' + row.jobName + '"任务吗?', "警告", {
        position: {
          top: 200,
          left: 'center'
        }
      })
        .then(type => {
          if (type === "confirm") {
            changeJobStatus(row.jobId, newStatus).then(() => {
              this.msgSuccess(text + "成功");
              row.status = newStatus;
            })
          }
        });
    },
    /* 立即执行一次 */
    handleRun(row) {
      this.confirm('确认要立即运行"' + row.jobName + '"任务吗?', "警告")
        .then(type => {
          if (type === 'confirm') {
            this.running = true
            return runJob(row.jobId, row.jobGroup).then(() => {
              this.notifySuccess("运行成功");
              this.running = false;
            });
          }
        }).then().catch(function() {});
    },
    /** 任务详细信息 */
    handleView(row) {
      getJob(row.jobId).then(response => {
        console.log(response)
        this.form = response.data;
        this.openView = true;
      });
    },
    /** 任务日志列表查询 */
    handleJobLog(jobId) {
      if (jobId) {
        this.$router.push({
          path: "/job/log",
          query: {
            jobId: jobId
          }
        });
      } else {
        this.$router.push("/job/log")
      }
    },
    /** 新增按钮操作 */
    handleAdd() {
      this.reset();
      this.open = true;
      this.title = "添加任务";
    },
    /** 修改按钮操作 */
    handleUpdate({ row }) {
      row = !!row ? row : this.currentRow
      this.reset();
      const jobId = row.jobId || this.ids;
      getJob(jobId).then(response => {
        this.form = response.data;
        this.open = true;
        this.title = "修改任务";
      });
    },
    /** 提交按钮 */
    submitForm: function() {
      this.$refs["form"].validate(valid => {
        if (valid) {
          if (this.form.jobId != undefined) {
            updateJob(this.form).then(response => {
              if (response.code === 200) {
                this.msgSuccess("修改成功");
                this.open = false;
                this.getList();
              }
            });
          } else {
            addJob(this.form).then(response => {
              if (response.code === 200) {
                this.msgSuccess("新增成功");
                this.open = false;
                this.getList();
              }
            });
          }
        }
      });
    },
    /** 删除按钮操作 */
    handleDelete(row) {
      row = !!row ? row : this.currentRow;
      const jobIds = row.jobId || this.ids;
      this.confirm('是否确认删除定时任务"' + row.jobName + '"？', "警告")
        .then(type => {
          if (type === 'confirm') {
            return delJob(jobIds).then(() => {
              this.getList();
              this.msgSuccess("删除成功");
            });
          }
        });
    },
    /** 导出按钮操作 */
    handleExport() {
      const queryParams = this.queryParams;
      this.confirm("是否确认导出所有定时任务数据项?", "警告")
        .then(type => {
          if (type === 'confirm') {
            return exportJob(queryParams).then(response => {
              this.download(response.msg);
            })
          }
        }).catch(function() {});
    }
  }
};
</script>
